package com.yc.cloud.wechat.pay.service.impl;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.app.AppServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.Amount;
import com.wechat.pay.java.service.payments.jsapi.model.Payer;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayRequest;
import com.wechat.pay.java.service.payments.jsapi.model.PrepayWithRequestPaymentResponse;
import com.wechat.pay.java.service.payments.jsapi.model.QueryOrderByOutTradeNoRequest;
import com.wechat.pay.java.service.payments.model.Transaction;
import com.yc.cloud.basic.exception.Asserts;
import com.yc.cloud.wechat.pay.dto.PayNotifyDto;
import com.yc.cloud.wechat.pay.dto.QueryOrderByOutTradeNoDto;
import com.yc.cloud.wechat.pay.dto.request.WxCreateOrderParam;
import com.yc.cloud.wechat.pay.enums.PayTypeEnums;
import com.yc.cloud.wechat.pay.service.WxPayService;
import com.yc.cloud.wechat.pay.utils.HttpServletUtils;
import com.yc.cloud.wechat.pay.vo.WxPrepayWithRequestPaymentVo;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.val;
import lombok.extern.slf4j.Slf4j;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    private JsapiServiceExtension jsapiServiceExtension;
    private AppServiceExtension appServiceExtension;
    private final RSAAutoCertificateConfig rsaAutoCertificateConfig;

    public WxPayServiceImpl(RSAAutoCertificateConfig rsaAutoCertificateConfig) {
        this.rsaAutoCertificateConfig = rsaAutoCertificateConfig;
        log.info("WxPayServiceImpl....");
    }

    @PostConstruct
    public void init() {
        jsapiServiceExtension = new JsapiServiceExtension.Builder().config(rsaAutoCertificateConfig).signType("RSA")
                .build(); // 不填默认为RSA
        appServiceExtension = new AppServiceExtension.Builder().config(rsaAutoCertificateConfig).build();
    }

    // @Override
    // public PrepayWithRequestPaymentResponse createOrder(WxCreateOrderParam param)
    // {
    // PrepayWithRequestPaymentResponse response = new
    // PrepayWithRequestPaymentResponse();
    // try {
    // PrepayRequest request = new PrepayRequest();
    // request.setAppid(param.getAppId());
    // request.setMchid(param.getMerchantId());
    // request.setDescription(param.getDescription());
    // request.setOutTradeNo(param.getOrderNo());
    // request.setNotifyUrl(param.getPayNotifyUrl());
    // Amount amount = new Amount();
    // amount.setTotal(param.getAmount());
    // request.setAmount(amount);
    // Payer payer = new Payer();
    // payer.setOpenid(param.getOpenId());
    // request.setPayer(payer);
    // log.info("请求预支付下单，请求参数：{}", JSONUtil.toJsonStr(request));
    // // 调用预下单接口
    // response = jsapiServiceExtension.prepayWithRequestPayment(request);
    // log.info("订单【{}】发起预支付成功，返回信息：{}", param.getOrderNo(), response);
    // return response;
    // } catch (HttpException e) { // 发送HTTP请求失败
    // log.error("微信下单发送HTTP请求失败，错误信息：{}", e.getHttpRequest());
    // // return R.error().message("下单失败");
    // } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
    // log.error("微信下单服务状态错误，错误信息：{}", e.getErrorMessage());
    // // return R.error().message("下单失败");
    // } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
    // log.error("服务返回成功，返回体类型不合法，或者解析返回体失败，错误信息：{}", e.getMessage());
    // }
    // return null;
    // }

    @Override
    public WxPrepayWithRequestPaymentVo createOrder(WxCreateOrderParam param) {
        val result = new WxPrepayWithRequestPaymentVo();
        try {
            // 微信小程序调用预下单接口
            if (param.getPayType().equals(PayTypeEnums.WECHAT_MINI.getCode())) {
                PrepayRequest request = new PrepayRequest();
                request.setAppid(param.getAppId());
                request.setMchid(param.getMerchantId());
                request.setDescription(param.getDescription());
                request.setOutTradeNo(param.getOrderNo());
                request.setNotifyUrl(param.getPayNotifyUrl());

                Amount amount = new Amount();
                amount.setTotal(param.getAmount());
                request.setAmount(amount);

                Payer payer = new Payer();
                payer.setOpenid(param.getOpenId());
                request.setPayer(payer);

                PrepayWithRequestPaymentResponse response = jsapiServiceExtension.prepayWithRequestPayment(request);
                log.info("订单【{}】发起微信小程序预支付成功，返回信息：{}", param.getOrderNo(), response);
                BeanUtils.copyProperties(response, result);
                // JSAPI提取prepay_id
                String packageVal = response.getPackageVal();
                String prepayId = extractPrepayId(packageVal);
                result.setPrepayId(prepayId);
                result.setTimestamp(response.getTimeStamp());
                result.setPartnerId(param.getMerchantId());
            }
            // 移动端调用微信支付预下单接口
            else {
                var request = new com.wechat.pay.java.service.payments.app.model.PrepayRequest();
                request.setAppid(param.getAppId());
                request.setMchid(param.getMerchantId());
                request.setDescription(param.getDescription());
                request.setOutTradeNo(param.getOrderNo());
                request.setNotifyUrl(param.getPayNotifyUrl());

                var amount = new com.wechat.pay.java.service.payments.app.model.Amount();
                amount.setTotal(param.getAmount());
                request.setAmount(amount);

                var response = appServiceExtension.prepayWithRequestPayment(request);
                log.info("订单【{}】发起微信移动端预支付成功，返回信息：{}", param.getOrderNo(), response);
                BeanUtils.copyProperties(response, result);
                result.setPartnerId(param.getMerchantId());
                result.setAppId(param.getAppId());
                result.setPaySign(response.getSign());
            }

        } catch (HttpException e) {
            log.error("微信下单发送HTTP请求失败，错误信息：{}", e.getHttpRequest());
            Asserts.fail("下单失败：HTTP请求异常");
        } catch (ServiceException e) {
            log.error("微信下单服务状态错误，错误信息：{}", e.getErrorMessage());
            log.error("参数信息: {}", JSONUtil.toJsonStr(param));
            Asserts.fail("下单失败：服务异常");
        } catch (MalformedMessageException e) {
            log.error("服务返回成功，返回体类型不合法，或者解析返回体失败，错误信息：{}", e.getMessage());
            Asserts.fail("下单失败：返回数据解析异常");
        } catch (Exception e) {
            log.error("创建订单发生未知异常", e);
            Asserts.fail("下单失败：系统异常");
        }
        return result;
    }

    @Override
    public PayNotifyDto payNotifyParser(HttpServletRequest request) {
        log.info("------收到支付通知------");
        // 请求头Wechatpay-Signature
        String signature = request.getHeader("Wechatpay-Signature");
        // 请求头Wechatpay-nonce
        String nonce = request.getHeader("Wechatpay-Nonce");
        // 请求头Wechatpay-Timestamp
        String timestamp = request.getHeader("Wechatpay-Timestamp");
        // 微信支付证书序列号
        String serial = request.getHeader("Wechatpay-Serial");
        // 签名方式
        String signType = request.getHeader("Wechatpay-Signature-Type");
        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder().serialNumber(serial).nonce(nonce).signature(signature)
                .timestamp(timestamp).signType(signType).body(HttpServletUtils.getRequestBody(request)).build();
        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(rsaAutoCertificateConfig);
        // 以支付通知回调为例，验签、解密并转换成 Transaction
        // log.info("验签参数：{}", requestParam);
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        log.info("验签成功！-支付回调结果：{}", transaction.toString());
        if (Transaction.TradeStateEnum.SUCCESS == transaction.getTradeState()) {
            // log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", transaction.getOutTradeNo(),
            // transaction.getTransactionId());
            // todo 是否还需要校验下商户号、appid等信息是否一致
            // if (wxPayConfig.getAppId().equals(transaction.getAppid()) &&
            // wxPayConfig.getMerchantId().equals(transaction.getMchid())) {
            return new PayNotifyDto(transaction.getOutTradeNo(), transaction.getTransactionId(),
                    transaction.getAmount().getTotal());
            // }
        }
        return null;
    }

    @Override
    public QueryOrderByOutTradeNoDto queryOrderByOutTradeNo(String orderNo, String merchantId) {
        QueryOrderByOutTradeNoRequest queryRequest = new QueryOrderByOutTradeNoRequest();
        queryRequest.setMchid(merchantId);
        queryRequest.setOutTradeNo(orderNo);
        Transaction result = jsapiServiceExtension.queryOrderByOutTradeNo(queryRequest);
        boolean paySuccess = false;
        if (Transaction.TradeStateEnum.SUCCESS == result.getTradeState()) {
            log.info("内部订单号【{}】,微信支付订单号【{}】支付成功", result.getOutTradeNo(), result.getTransactionId());
            paySuccess = true;
        }
        return new QueryOrderByOutTradeNoDto(result.getOutTradeNo(), result.getTransactionId(), paySuccess);
    }

    private String extractPrepayId(String packageVal) {
        if (StrUtil.isNotEmpty(packageVal)) {
            String[] parts = packageVal.split("=");
            if (parts.length == 2 && "prepay_id".equals(parts[0])) {
                return parts[1];
            }
        }
        return null;
    }
}
